package com.report;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.report.common.DataSet;
import com.report.common.DataSetLoader;
import com.report.common.DbDataSetLoader;
import org.apache.commons.collections.CollectionUtils;
import org.jxls.common.Context;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import java.util.Map;

public class TemplateContext {

    private static final Logger logger = LoggerFactory.getLogger(TemplateContext.class);
    private final DataSource dataSource;
    private Context _inner_context = new Context();
    private Map<String, String> params;
    private DataSetLoader dataSetLoader;


    public TemplateContext(DataSource dataSource, Map<String, String> params) {
        this.dataSource = dataSource;
        this.params = params;
        this.dataSetLoader = new DbDataSetLoader(dataSource);
        this.put("_params", params);
        this.put("_time", new Date());
    }

    public void putFunctionComponent(Object funObject) {
        put("$", funObject);
    }

    public void loadDataSets(TemplateType type,List<String> nameList) {
        if (this.dataSetLoader == null) return;
        if (CollectionUtils.isEmpty(nameList)) return;
        if (nameList.get(0).equals("all")) {
            nameList.clear();
        }
        List<DataSet> list = this.dataSetLoader.load(type,nameList);
        if (list != null) {
            for (DataSet ds : list) {
                switch (ds.getType()) {
                    case SQL:
                        this.putSqlData(ds.getName(), ds.getData());
                        break;
                    case JSON:
                        this.putJsonData(ds.getName(), ds.getData());
                        break;
                    case TEXT:
                        this.put(ds.getName(), ds.getData());
                        break;
                    default:
                        break;
                }
            }
        }
    }

    public void put(String key, Object value) {
        this._inner_context.putVar(key, value);
    }

    public void putSqlData(String key, String sql) {
        this.putSqlData(key, sql, this.dataSource);
    }

    public void putSqlData(String key, String sql, DataSource dataSource) {
//        this.put(key, new TemplateSqlData(Tools.applySql(sql, params), dataSource));
        try {
            this.put(key, Tools.dbQuery(dataSource,Tools.applySql(sql, params)));
        } catch (SQLException e) {
            logger.error(String.format("query data by dataSource fail:%s", key), e);
        }
    }

    public void putJsonData(String key, String json) {
        try {
            ObjectMapper mapper = new ObjectMapper();
            Map<String, Object> d = mapper.readValue(json, new TypeReference<Map<String, Object>>() {
            });
            this.put(key, d);
        } catch (Exception ex) {
            logger.error(String.format("JSON data convert fail:%s", key), ex);
        }
    }

    public DataSource getDataSource() {
        return this.dataSource;
    }

    public Map<String, Object> getData() {
        return this._inner_context.toMap();
    }

    public Context getInnerContext() {
        return this._inner_context;
    }

    public void clearContext(){
        this._inner_context = null;
    }

    public Map<String, String> getParams() {
        return this.params;
    }

    public void setParams(Map<String, String> params) {
        this.params = params;
    }

    public DataSetLoader getDataSetLoader() {
        return dataSetLoader;
    }

    public void setDataSetLoader(DataSetLoader dataSetLoader) {
        this.dataSetLoader = dataSetLoader;
    }
}
